﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Printing;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using ZuesControls.Commons;
using ZuesControls.Helpers;
using ZuesControls.Interfaces;

namespace ZuesControls.Controls
{
    /// <summary>
    ///  加载中
    /// </summary>
    [TemplatePart(Name = MessageTextPartName, Type = typeof(TextBlock))]
    public class ZSLoading : ContentControl, ILoading
    {
        private Border PART_Border;

        /// <summary>
        /// 消息文本名称
        /// </summary>
        public const string MessageTextPartName = "Path_MessageText";

        static ZSLoading()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ZSLoading), new FrameworkPropertyMetadata(typeof(ZSLoading)));
        }

        /// <summary>
        /// 边框厚度
        /// </summary>
        public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
            "StrokeThickness", typeof(double), typeof(ZSLoading), new PropertyMetadata(default(double)));

        /// <summary>
        /// 虚线和间隙的值的集合
        /// </summary>
        public static readonly DependencyProperty StrokeDashArrayProperty = DependencyProperty.Register(
            "StrokeDashArray", typeof(DoubleCollection), typeof(ZSLoading), new PropertyMetadata(default(DoubleCollection)));

        /// <summary>
        /// 聚焦颜色
        /// </summary>
        public static readonly DependencyProperty FocusedBrushProperty = DependencyProperty.RegisterAttached(
            "FocusedBrush", typeof(Brush), typeof(ZSLoading), new PropertyMetadata(default(Brush)));

        /// <summary>
        /// 进度
        /// </summary>
        public static readonly DependencyProperty ProgressProperty = DependencyProperty.Register(
            "Progress", typeof(double), typeof(ZSLoading), new PropertyMetadata(default(double), OnProgressChanged));

        /// <summary>
        /// 直径
        /// </summary>
        public static readonly DependencyProperty DiameterProperty = DependencyProperty.RegisterAttached(
            "Diameter", typeof(double), typeof(ZSLoading), new PropertyMetadata(default(double)));

        /// <summary>
        /// 边框厚度
        /// </summary>
        public double StrokeThickness
        {
            get { return (double)GetValue(StrokeThicknessProperty); }
            set { SetValue(StrokeThicknessProperty, value); }
        }

        /// <summary>
        /// 虚线和间隙的值的集合
        /// </summary>
        public DoubleCollection StrokeDashArray
        {
            get { return (DoubleCollection)GetValue(StrokeDashArrayProperty); }
            set { SetValue(StrokeDashArrayProperty, value); }
        }

        /// <summary>
        /// 聚焦颜色
        /// </summary>
        public Brush FocusedBrush
        {
            get { return (Brush)GetValue(FocusedBrushProperty); }
            set { SetValue(FocusedBrushProperty, value); }
        }

        /// <summary>
        /// 进度
        /// </summary>
        public double Progress
        {
            get { return (double)GetValue(ProgressProperty); }
            set { SetValue(ProgressProperty, value); }
        }

        private static void OnProgressChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var loading = d as ZSLoading;
            loading.StrokeDashArray = new DoubleCollection(new List<double> { (loading.Diameter - loading.StrokeThickness) * Math.PI / loading.StrokeThickness * loading.Progress, double.MaxValue });
        }



        /// <summary>
        /// 直径
        /// </summary>
        public double Diameter
        {
            get { return (double)GetValue(DiameterProperty); }
            set { SetValue(DiameterProperty, value); }
        }


        public async Task<OperateResult<T>> InvokeAsync<T>(Func<CancellationToken, Task<OperateResult<T>>> func, CancellationToken cancellationToken = default)
        {
            this.Dispatcher.Invoke(() =>
            {
                this.Visibility = Visibility.Visible;
              
            });
            return await await Task.Factory.StartNew(async () =>
            {
                try
                {
                    return await func?.Invoke(cancellationToken);
                }
                catch (Exception ex)
                {
                    return OperateResult.CreateFailResult<T>(ex.Message);
                }
                finally
                {
                    this.Dispatcher.Invoke(() =>
                    {
                        this.Visibility = Visibility.Collapsed;
                    });
                }
            }, cancellationToken);
        }

        public async Task<OperateResult> InvokeAsync(Func<CancellationToken, Task<OperateResult>> func, CancellationToken cancellation = default)
        {
            this.Dispatcher.Invoke(() =>
            {
                PART_Border ??= VisualHelper.TryFindParent<Border>(this);
                this.Visibility = Visibility.Visible;
                PART_Border.Visibility = Visibility.Visible;

            });
            return await await Task.Factory.StartNew(async () =>
            {
                try
                {
                    return await func?.Invoke(cancellation);
                }
                catch (Exception ex)
                {
                    return OperateResult.CreateFailResult(ex.Message);
                }
                finally
                {
                    this.Dispatcher.Invoke(() =>
                    {
                        PART_Border ??= VisualHelper.TryFindParent<Border>(this);
                        this.Visibility = Visibility.Collapsed;
                        PART_Border.Visibility = Visibility.Collapsed;

                    });
                }
            }, cancellation);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
           
        }

        public void ShowLoading()
        {
            PART_Border ??= VisualHelper.TryFindParent<Border>(this);
            this.Dispatcher.Invoke(() =>
            {
                this.Visibility = Visibility.Visible;
                PART_Border.Visibility = Visibility.Visible;
            });
        }
        public void HideLoading()
        {
            PART_Border ??= VisualHelper.TryFindParent<Border>(this);
            this.Dispatcher.Invoke(() =>
            {
                this.Visibility = Visibility.Collapsed;
                PART_Border.Visibility = Visibility.Collapsed;
            });
        }

    }
}
